﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// Reviewed
#pragma once

#include "GcmpModelInterface.h"
#include "RuntimeId.h"
#include "DocumentSaveError.h"
#include "ElementsChangeEventType.h"
#include "UndoRedoElementsChangeEventType.h"
#include "IObject.h"
#include "GcmpApiDeclaration.h"

namespace gcmp
{
    class IElement;
    class ElementId;
    class IElementManager;
    class IRegenerator;
    class IGraphicsMaterialManager;
    class IGisMap;
    class UniIdentity;
    class IElementsChangeEventHandler;
    class IElementVisibilityFilter;
    class IGraphicsStyleManager;
    class IElementVisibilityFilterManager;
    class IUndoRedoElementsChangeEventHandler;
    class ITransactionEvent;
    class IUndoRedoEvent;
    class ISpecificDbElementEvent;
    class IElementFilter;
    class IClonedElementPostProcessor;
    class IElementModelShapeChangeEvent;
    class IEditModeEvent;
    class IElementHiddenEdgeEvent;
    class IUidTree;
    class IGdcLinkModelViewManager;
    class IElementsChangeEventArgs;
    class ITransactionEventArgs;
    class IElementVersionManager;
    class IElementOwnerManager;
    class IElementEditPrivilegeManager;
    class IElementOccupantManager;
    class IElementRelationshipsVersionManager;
    class IElementLoadFilter;
    class IElementVisibilityController;
    class IElementDeletionContext;
    class IAutoSaveEventHandler;
    class IAutoSaveEvent;
    class IAllElementHiddenEdgeFinishEvent;
    class IZebraManager;
    class ICurvatureGraphManager;
    
    /// \brief 文档，包含模型所有数据的类，生命周期从新建/打开到关闭文档
    /// 
    /// 操作文档中对象，可通过GetElement接口拿到Element对象进行
    /// 要打开，保存，关闭文档可查看IDocumentManager
    FINAL_INTERFACE class GCMP_MODEL_INTERFACE_EXPORT IDocument: public IObject
    {
        DEFINE_CAST_DERIVED(gcmp::IDocument, gcmp::IObject); 
    public:
        /// \brief 析构函数
        virtual ~IDocument() {};

#pragma region 对象管理
        /// \brief 获取文档中除在IGroupType外所有IElement
        /// \return 文档中除在IGroupType外所有IElement
        /// \see IGroupType.h
        virtual std::vector<IElement*> GetAllElements() const = 0;

        /// \brief 获取文档中所有IElement
        /// \return 文档中所有IElement，性能
        virtual std::vector<IElement*> GetAllElementsIncludingInGroupType() const = 0;

        /// \brief 克隆Element对象
        /// \param pSourceElement 来源对象，可以是同文档或跨文档
        /// \param pOldToNewIdTable Element的id旧到新对照表
        /// \param pPostProcessor 拷贝后处理器
        /// \return 克隆出来的新对象ID
        virtual ElementId Clone(const IElement* pSourceElement
            , const std::unordered_map<ElementId, ElementId, ElementIdHash>* pOldToNewIdTable = nullptr, IClonedElementPostProcessor* pPostProcessor = nullptr) = 0;

        /// \brief 根据ElementId获取相应的IElement
        /// \param elementId 想得到的Element的id
        /// \return 得到的IElement的指针
        virtual IElement* GetElement(const ElementId& elementId) const = 0;

        /// \brief 根据classUid获取相应唯一的IElement
        /// \param classUid 单例IElement类对应的classUid
        /// \return 得到的IElement的指针
        virtual IElement* GetUniqueElementByClassUid(const UniIdentity& classUid) const = 0;

        /// \brief 向文档中添加一组带ElementId的Element
        /// 
        /// \param opElements 被添加的Elements
        /// \return 返回true表示添加成功，否则表示失败（如ElementId无效等）
        virtual bool AddElementsWithElementId(std::vector<OwnerPtr<IElement>>& opElements) = 0;

        /// \brief 根据ElementId删除IElement
        /// \param elementId 要删除的Element的id
        /// \param cannotDeleteExplanation 无法删除时的输出信息
        /// \return 成功返回true，失败返回false
        virtual bool DeleteElement(const ElementId& elementId, std::wstring* cannotDeleteExplanation = nullptr) = 0;

        /// \brief 根据ElementIds删除IElements->Element
        /// \param elementIds 要删除的Elements的ids
        /// \param cannotDeleteExplanation 无法删除时的输出信息
        /// \return 成功返回true，失败返回false
        virtual bool DeleteElements(const std::vector<ElementId>& elementIds, std::wstring* cannotDeleteExplanation = nullptr) = 0;

        /// \brief 根据ElementIds删除IElements
        ///
        /// 如果待删除的element有多个，那么能被删除的element将被删除，不能被删除的将不会删除同时返回错误
        /// 如果所有elements都被成功删除，返回true，否则返回false
        ///
        /// \param elementIds 要删除的Elements的ids
        /// \param errorMessages 无法删除时的输出信息。返回false时，返回删除失败的对象的id及其错误信息
        /// \return 成功返回true，失败返回false
        virtual bool DeleteElements(const std::vector<ElementId>& elementIds, std::map<ElementId, std::wstring>& errorMessages) = 0;

        /// \brief 通过Element的实现UniIdentity，获得此类别的所有除在GroupType内的Element
        ///
        /// 获得文档下所有实现号为implementationUid的除在GroupType内的Element
        /// \param implementationUid 实现的UniIdentity
        /// \return 此类别所有的除在GroupType内的Element
        /// \see IGroupType.h
        virtual std::vector<IElement*> GetElementsByImplementationUid(
            const UniIdentity& implementationUid) const = 0;

        /// \brief 通过Element的实现UniIdentity，获得此类别的所有Element
        ///
        /// 获得文档下所有实现号为implementationUid的Element
        /// \param implementationUid 实现的UniIdentity
        /// \return 此类别所有的Element
        virtual std::vector<IElement*> GetElementsByImplementationUidIncludingInGroupType(
            const UniIdentity& implementationUid) const = 0;

        /// \brief 通过某类别的类别UniIdentity，获得此类别的所有除在GroupType内的Element
        ///
        /// 获得文档下所有类别号为categoryUid的除在GroupType内的Element
        /// \param categoryUid 类别的UniIdentity
        /// \return 此类别所有的除在GroupType内的Element
        virtual std::vector<IElement*> GetElementsByCategory(const UniIdentity& categoryUid) const = 0;

        /// \brief 通过某类别的类别UniIdentity，获得此类别的所有Element
        ///
        /// 获得文档下所有类别号为categoryUid的Element
        /// \param categoryUid 类别的UniIdentity
        /// \return 此类别所有的Element
        virtual std::vector<IElement*> GetElementsByCategoryIncludingInGroupType(const UniIdentity& categoryUid) const = 0;

        /// \brief 通过某标准分类属性编码及引用的分类编码获取所有的Element
        ///
        /// 获得文档下所有具有该标准分类属性编码及引用的分类编码的Element。
        /// \param attributeCode 标准分类属性编码
        /// \param classificationCode 标准分类编码。为空代表只要含有attributeCode参数，不判断classificationCode的值。
        /// \return 返回所有的满足具有attributeCode属性编码并且其值是referenceClassificationCode的Element
        virtual std::vector<IElement*> GetElementsByStandardClassificationCode(
            const std::wstring& attributeCode,
            const std::wstring& classificationCode
        ) const = 0;

        /// \brief 通过多组标准分类属性编码及引用的分类编码，获得Elements
        /// \param attributeCodeToClassificationCode 标准分类属性编码到分类编码的映射
        /// \return 返回找到的Elements
        virtual std::unordered_map<std::wstring, std::vector<IElement*>> GetElementsByStandardClassificationCodes(
            const std::unordered_map<std::wstring, std::wstring>& attributeCodeToClassificationCode
        ) const = 0;

        /// \brief 创建一个cache，存储标准分类属性编码到对应Element的映射
        /// \param attributeCode 各专业指定的"标准分类"属性的编码
        /// \note 创建缓存后，再调用接口GetElementsByStandardClassificationCode，从缓存中拿Element
        virtual void BuildCacheForElementWithStandardClassificationCode(const std::wstring& attributeCode) = 0;

        /// \brief 清除存储标准分类属性编码到对应Element的映射的缓存
        ///
        /// \note 清除后，如期望加速查找，须再次创建缓存
        virtual void ClearCacheForElementWithStandardClassificationCode() = 0;

        /// \brief 通过某类别的类别UniIdentity，获得此类别的所有除在GroupType内的Element
        ///
        /// 获得文档下所有类别号为categoryUid的除在GroupType内的Element，并且可以通过过滤器进行过滤
        /// \param categoryUid 类别的UniIdentity
        /// \param pFilter 元素过滤器，nullptr 则不做过滤
        /// \return 此类别所有的经过过滤的Element
        /// \see GroupType.h
        virtual std::vector<IElement*> GetElementsByCategory(const UniIdentity& categoryUid, const IElementFilter* pFilter) const = 0;

        /// \brief 通过某类别的类别UniIdentity，获得此类别的所有Element
        ///
        /// 获得文档下所有类别号为categoryUid的Element，并且可以通过过滤器进行过滤
        /// \param categoryUid 类别的UniIdentity
        /// \param pFilter 元素过滤器，nullptr 则不做过滤
        /// \return 此类别所有的经过过滤的Element
        virtual std::vector<IElement*> GetElementsByCategoryIncludingInGroupType(const UniIdentity& categoryUid, const IElementFilter* pFilter) const = 0;

        /// \brief 获取当前文档中所有辅助对象
        /// \return 当前文档中所有辅助对象
        virtual std::vector<IElement*> GetAllAuxiliaryElements() = 0;
#pragma endregion

#pragma region 信息
        /// \brief 获取RuntimeId，
        ///
        /// 此RuntimeId不序列化，每次打开文档值不相同
        /// \return 有改动返回true，无改动返回false //修改
        virtual RuntimeId GetRuntimeId() const = 0;

        /// \brief 获取文件所在路径(包括文档名称)
        ///
        /// 若是未保存过的新文档，路径是系统临时文件路径
        /// \return 文件所在路径
        virtual std::wstring GetFilePath() const = 0;

        /// \brief 获取文档名称
        /// \return 文档名称
        virtual std::wstring GetName() const = 0;

        /// \brief 设置文档名称
        /// \param name 文档名称
        /// \return 成功返回true，失败返回false
        virtual bool SetName(const std::wstring& name) = 0;

        /// \brief 重命名文档名称(仅协同使用)
        /// \note 以模板文件作为初始内容打开空工作单元时, 将Doc的名字重新设置为工作单元的名字, 使两者保持一致。
        /// \param name 文档名称
        /// \return 成功返回true，失败返回false
        virtual bool ReName(const std::wstring& name) = 0;

        /// \brief 设置文档为只读
        /// 
        /// 只读文档不允许保存（如打开一个已处于打开状态的文档）
        /// \return void
        virtual void SetIsReadonlyForSharingViolation(bool isFileReadOnly) = 0;

        /// \brief 文档是否为只读
        /// 
        /// 只读文档不允许保存（如打开一个已处于打开状态的文档）
        /// \return 只读返回true，否则返回false
        virtual bool IsReadonlyForSharingViolation() const = 0; //saveError中加一项ReadOnly

        /// \brief 文档是否为只读模式
        /// \
        /// \ 该模式下没有写权限，只能以只读模式，不允许修改、保存、另存为
        /// \return bool 只读模式返回true，否则返回false
        virtual bool IsReadonlyWithNoTransactionAndNoSave() const = 0;

        /// \brief 是否为族文档
        /// \return 是族文档返回true，不是返回false
        virtual bool IsFamilyDocument() const = 0;

        /// \brief 是否是主文档
        ///
        /// 一个项目有且只有一个主文档（界面上可见的文档）; 一个主文档可以有若干嵌套文档
        /// \return 是主文档返回true，不是返回false
        virtual bool IsMainDocument() const = 0;

        /// \brief 是否是数据文档
        ///
        /// 数据文档不需要对象和文档的升级
        /// \return 是主文档返回true，不是返回false
        virtual bool IsDataDocument() const = 0;

        /// \brief 判断文档是否是链接文档
        ///
        /// \return bool true表示是链接文档，false表示不是链接文档
        virtual bool IsLinked() const = 0;

        /// \brief 判断文档是否需要处理被链接的模型
        ///
        /// \return bool true-需要；false-不需要
        virtual bool NeedHandleLinkedModel() const = 0;
#pragma endregion

#pragma region 事件管理
        /// \brief 添加Element改变事件的处理者
        /// \param eventType 事件类型
        /// \param pHandler 事件处理者
        /// \return 返回true表示添加成功，否则表示失败
        virtual bool AddElementsChangeEventHandler(ElementsChangeEventType eventType, IElementsChangeEventHandler* pHandler) = 0;

        /// \brief 删除Element改变事件的处理者
        /// \param eventType 事件类型
        /// \param pHandler 事件处理者
        /// \return 返回true表示删除成功，否则表示失败
        virtual bool DeleteElementsChangeEventHandler(ElementsChangeEventType eventType, IElementsChangeEventHandler* pHandler) = 0;

        virtual bool DeleteAutoSaveEventHandler(IAutoSaveEventHandler* pHandler) = 0;

        virtual bool AddAutoSaveEventHandler(IAutoSaveEventHandler* pHandler) = 0;

        virtual IAutoSaveEvent* GetAutoSaveEvent() = 0;
        /// \brief 获取事务事件
        ///
        /// \return 事务事件
        virtual ITransactionEvent* GetTransactionEvent() = 0;

        /// \brief 获取Undo/Redo事件
        ///
        /// \return Undo/Redo事件
        virtual IUndoRedoEvent* GetUndoRedoEvent() = 0;

        /// \brief 获取EditMode事件
        ///
        /// \return EditMode事件
        virtual IEditModeEvent* GetEditModeEvent() = 0;

        /// \brief 获取特定元素事件
        ///
        /// 当前发出的事件有 ModelView的创建和销毁事件
        ///
        /// \return SpecificDbElement事件
        virtual ISpecificDbElementEvent* GetSpecificDbElementEvent() = 0;


        /// \brief 获取Element的ModelGrep的改变事件
        ///
        /// \return Element的ModelGrep的改变时间
        virtual IElementModelShapeChangeEvent* GetElementModelShapeChangeEvent() = 0;

        /// \brief 获取Element的消隐事件
        ///
        /// \return Element的消隐事件
        virtual IElementHiddenEdgeEvent* GetElementHiddenEdgeEvent() = 0;

        /// \brief 获取当前文档所有Element的消隐结束事件
        ///
        /// \return 所有Element的消隐结束事件
        virtual IAllElementHiddenEdgeFinishEvent* GetAllElementHiddenEdgeFinishEvent() = 0;
#pragma endregion

#pragma region 文档数据管理
        /// \brief 保存文档到当前文件
        ///
        /// 需要先调用SaveAs()给出文件路径
        /// \param saveOptions 保存选项
        /// \param saveResult 文档保存结果：包括错误码及对应信息
        /// \return 成功返回true，失败返回false
        /// \see SaveAs()
        virtual bool Save(const DocumentSaveOptions & saveOptions, DocumentSaveResult & saveResult) = 0;

        /// \brief 另存文档
        ///
        /// 如有后续修改和保存，修改会存入这里指定的路径
        /// \param filePath 文档另存的路径
        /// \param saveOptions 保存选项
        /// \param saveResult 文档保存结果：包括错误码及对应信息
        /// \return 成功返回true，失败返回false
        virtual bool SaveAs(const std::wstring & filePath, const DocumentSaveOptions & saveOptions, DocumentSaveResult & saveResult) = 0;

        /// \brief 备份文档到指定文件
        ///
        /// 和SaveAs()不同，BackupToFile()不改变当前文件，如有后续修改和保存，修改还会存入当前文件。
        /// BackupToFile()不影响当前文档状态。
        /// \param filePath 文档存入的路径。不能和当前路径相同，否则返回false和DocumentSaveError::InvalidPath错误码。
        /// \param saveResult 文档保存结果：包括错误码及对应信息
        /// \return 成功返回true，失败返回false
        /// \see SaveAs()
        virtual bool BackupToFile(const std::wstring& filePath, DocumentSaveResult& saveResult) = 0;

        /// \brief 保存文档中指定的element到指定的文件
        ///
        /// 不改变当前文件，如有后续修改和保存，修改还会存入当前文件。
        /// 此接口不影响当前文档状态。
        /// \param vElementIds 要保存的ElementID;
        /// \param materialGuidStrings 要保存的Element使用的材质guid;
        /// \param familyFiles 要保存的族的族名称
        /// \param filePath 文档存入的路径。不能和当前路径相同，否则返回false和DocumentSaveError::InvalidPath错误码。
        /// \param saveResult 文档保存结果：包括错误码及对应信息
        /// \return 成功返回true，失败返回false
        /// \see SaveAs()
        virtual bool Save(const std::vector<ElementId>& vElementIds, const std::set<std::wstring>& materialGuidStrings, const std::set<std::wstring>& familyFiles, std::wstring& filePathName, DocumentSaveResult& saveResult) = 0;

        /// \brief 备份数据集关联的文档到新文档中
        ///
        /// 不改变当前数据集关联的文档，如有后续修改和保存，修改还会存入当前文档。
        /// 备份出的文档将以IDocument对象形式提供
        /// \param filePath 备份的新文档路径，以.gac结尾，如果路径已存在则覆盖，如果路径文件已存在并处于打开状态则不备份返回nullptr
        /// \param datasetSubId 新数据集的Sub-Id
        /// \param saveResult 文档保存结果：包括错误码及对应信息
        /// \return 成功返回新的文档智能指针，失败返回nullptr
        virtual IDocument* BackupForDataset(const std::wstring& filePath, UInt16 datasetSubId, DocumentSaveResult& saveResult) = 0;

        /// \brief 文档是否已保存过
        ///
        /// 保存过指已经指定过保存位置路径，无需再次指定保存位置；若当前打开的是一个已有的历史文档，也属于保存过
        /// \return 已保存过返回true，没有返回false
        virtual bool GetWasSaved() const = 0;

        /// \brief 文档是否在上次保存后有改动
        /// \return 有改动返回true，无改动返回false
        virtual bool IsChangedAfterPreviousSave() const = 0;

        /// \brief 设置文档是否在上次保存后有改动
        ///
        /// 这里只是设置了文档的一个标记位，比如在UI文档关闭时，想忽略一些文档初始化引起的改动，可调用此方法
        /// \param isChanged 是否有改动
        /// \return void
        virtual void SetIsChangedAfterPreviousSave(bool isChanged) = 0;
#pragma endregion

#pragma region 关联更新
        /// \brief 获取文档关联更新器
        /// \return 文档关联更新器
        virtual IRegenerator* GetRegenerator() = 0;
#pragma endregion

#pragma region GIS操作
        virtual IGisMap* GetGisMap() = 0;
#pragma endregion

#pragma region 事务
        /// \brief 是否在事务撤消中
        /// \return 是返回true，不是返回false
        virtual bool IsInTransactionUndo() const = 0;

        /// \brief 是否在事务重做中
        /// \return 是返回true，不是返回false
        virtual bool IsInTransactionRedo() const = 0;

        /// \brief 是否在事务回滚中
        /// \return 是返回true，不是返回false
        virtual bool IsInTransactionRollback() const = 0;

        /// \brief 获取当前文档中变化的Elements
        ///
        /// 获得文档下所有增加的、删除的、修改的Elements
        /// \param addedElements 输出增加的Element ids
        /// \param deletedElements 输出删除的Element ids
        /// \param modifiedElements 输出修改的Element ids
        /// \return 如果有变化， 返回true, 否则false
        virtual bool GetIncrementalElements(std::set<ElementId>& addedElements, std::set<ElementId>& deletedElements, std::set<ElementId>& modifiedElements) const = 0;
#pragma endregion

#pragma region 显示相关管理器
        /// \brief 获取图形材质管理器
        /// \return 图形材质管理器
        virtual IGraphicsMaterialManager* GetGraphicsMaterialManager() = 0;

        /// \brief 获取图形材质管理器
        /// \return 图形材质管理器
        virtual const IGraphicsMaterialManager* GetGraphicsMaterialManager() const = 0;

        /// \brief 获取图形样式管理器
        /// \return 图形样式管理器
        virtual IGraphicsStyleManager* GetGraphicsStyleManager() = 0;

        /// \brief 获取图形样式管理器
        /// \return 图形样式管理器
        virtual const IGraphicsStyleManager* GetGraphicsStyleManager() const = 0;

        /// \brief 获取可见性管理器
        ///
        /// \return 可见性管理器
        virtual IElementVisibilityFilterManager* GetElementVisibilityFilterManager() = 0;

        /// \brief 获取可见性管理器
        ///
        /// \return 可见性管理器
        virtual const IElementVisibilityFilterManager* GetElementVisibilityFilterManager() const = 0;

        /// \brief 获取最终可见性控制器
        ///
        /// \return 可见性控制器
        virtual const IElementVisibilityController* GetElementVisibilityController() const = 0;

        /// \brief 获取最终可见性控制器
        ///
        /// \return 可见性控制器
        virtual IElementVisibilityController* GetElementVisibilityController() = 0;

        /// \brief 设置最终可见性控制器
        /// \param opElementVisiblilityController 需要设置的最终可见性控制器
        virtual void SetElementVisibilityController(OwnerPtr<IElementVisibilityController> opElementVisiblilityController) = 0;

        /// \brief 获取链接视图管理器（跨专业）
        ///
        /// \return 链接视图管理器
        virtual IGdcLinkModelViewManager* GetLinkModelViewManager() = 0;

        /// \brief 获取链接视图管理器（跨专业）
        ///
        /// \return 链接视图管理器
        virtual const IGdcLinkModelViewManager* GetLinkModelViewManager() const = 0;

        /// \brief 获取斑马纹效果管理器
        virtual IZebraManager* GetZebraManager() = 0;

        /// \brief 获取斑马纹效果管理器
        virtual const IZebraManager* GetZebraManager() const = 0;

        /// \brief 获取曲率云图效果管理器
        virtual ICurvatureGraphManager* GetCurvatureGraphManager() = 0;

        /// \brief 获取曲率云图效果管理器
        virtual const ICurvatureGraphManager* GetCurvatureGraphManager() const = 0;
#pragma endregion

#pragma region 构件级协同原型
        /// \brief 是否在构件级协同环境下
        /// \return  true - 是；false - 否
        virtual bool IsInCollaborationEnvironment() const = 0;

        /// \brief 向文档中加入对象
        ///
        /// 不同于AddElementsWithElementId，不会自动计算传入的opElements中，通过ElementId引用的其它对象。
        ///
        /// \param opElements。希望添加的对象，这些对象已经有Id
        /// \param pElementLoadFilter。加载过滤器，不能为空
        /// \bool 是否添加成功。如果opElements为空，返回false
        /// \see AddElementsWithElementId
        virtual bool LoadElements(std::vector<std::pair<OwnerPtr<IElement>, Int32>> & opElements, IElementLoadFilter * pElementLoadFilter) = 0;

        /// \brief 获取文档的主工作单元
        /// \return 工作单元Id
        virtual const std::wstring & GetOwnerDatasetId() const = 0;

        /// \brief 获取Element版本管理器
        ///
        /// \return Element版本管理器
        virtual IElementVersionManager* GetElementVersionManager() = 0;

        /// \brief 获取Element版本管理器
        ///
        /// \return Element版本管理器
        virtual const IElementVersionManager* GetElementVersionManager() const = 0;

        /// \brief 获取ElementOwner管理器
        ///
        /// \return ElementOwner管理器
        virtual IElementOwnerManager* GetElementOwnerManager() = 0;

        /// \brief 获取ElementOwner管理器
        ///
        /// \return ElementOwner管理器
        virtual const IElementOwnerManager* GetElementOwnerManager() const = 0;

        /// \brief 获取Element编辑权限管理器
        ///
        /// \return ElementOwner管理器
        virtual IElementEditPrivilegeManager* GetElementEditPrivilegeManager() = 0;

        /// \brief 获取Element编辑权限管理器
        ///
        /// \return ElementOwner管理器
        virtual const IElementEditPrivilegeManager* GetElementEditPrivilegeManager() const = 0;

        /// \brief 获取Element的占用者管理器
        ///
        /// \return Element占用者管理器
        virtual IElementOccupantManager* GetElementOccupantManager() = 0;

        /// \brief 获取Element的占用者管理器
        ///
        /// \return Element占用者管理器
        virtual const IElementOccupantManager* GetElementOccupantManager() const = 0;

        /// \brief 获取Element的强弱关系版本管理器
        ///
        /// \return Element的强弱关系版本管理器
        virtual IElementRelationshipsVersionManager* GetElementRelationshipsVersionManager() = 0;

        /// \brief 获取Element的强弱关系版本管理器
        ///
        /// \returnElement的强弱关系版本管理器
        virtual const IElementRelationshipsVersionManager* GetElementRelationshipsVersionManager() const = 0;

        /// \brief 获得meta文件以及其中ClassSchemas的MD5值
        /// \param[out] metaFilePath meta文件路径
        /// \param[out] MD5OfMetaFileClassSchemas meta文件中ClassSchema的MD5值
        /// \return void
        virtual void GetMetaFileAndItsClassSchemasMD5(std::wstring& metaFilePath, std::string& MD5OfMetaFileClassSchemas) = 0;

        /// \brief 是否是为初始化构件级协同用的模板文档
        /// \return 是-true；否-false
        virtual bool IsTemplateToInitializeElementCollaborationProject() const = 0;

        /// \brief 产品端需要调用此接口设置专业。否则平台调用协同功能时，获取不到专业信息。
        virtual bool SetMajorType(const std::wstring & majorType) = 0;

        /// \brief 获取专业
        virtual const std::wstring & GetMajorType() const = 0;

        /// \brief 对象是否是最新版本
        /// \param id 对象id
        /// \return true-最新版本；false-不是最新版本
        virtual bool IsElementLastestVersion(const ElementId & id) const = 0;

        /// \brief 如果当前正在调用DeleteElementImp,通过此函数获ElementDeletionContext
        /// \return nullptr 表明还未产生IElementDeletionContext,或者DeleteElementImp已经结束
        /// 返回值非空,表明可以使用
        virtual  const IElementDeletionContext* GetCurrentElementDeletionContext() const = 0;

        /// \brief 获取短Id替换后的新id,如果没有就返回输入id
        /// \param id 对象替换前的id
        /// \return 对象替换后的ElementId
        virtual ElementId GetCorrectIdByReplaceRecords(ElementId& id) =0;

        /// \brief 根据Id的整型数据，查找IElement.本函数将忽略datasetid,只能用在本地环境中
        /// \param id 对象id
        /// \return 搜索到的IElement,如果没有查到为nullptr
        virtual IElement* GetElementByStoreIndex(UInt64 intid) = 0;

        /// \brief 原来依赖Element A的所有Element都切换到依赖Element B
        /// \param pElement 需要替换依赖的Element
        /// \param originid 待替换的Element A 的Id。
        /// \param newid 替换的目标Element B 的Id
        /// \return 执行结果。替换失败返回false；替换成功返回true
        virtual void ReplaceRefElementId(IElement* pElement, ElementId originid, ElementId newid) = 0;
#pragma endregion

#pragma region 管综-多文档编辑
        /// \brief 将数据层的改动主动发送给Host文档
        ///
        /// 事务提交时，数据改动会发送给Host文档，不需要调用此接口；
        /// 适用于需要将中间过程的数据实时发送给Host文档，比如用即将rollback的数据做预览的场景；
        /// \return 执行结果
        virtual bool PopulateChangesToHostDocument() = 0;

        /// \brief 判断链接文档是否可编辑
        ///
        /// 适用于管综同时载入等场景，区分于传统链接行为
        /// \return true，可编辑; false，不可编辑
        virtual bool IsEditableWhenLinked() const = 0;

        /// \brief 获取未加载的ElementId集合(未加载：反序列化过滤，未创建的element对象)
        virtual bool GetUnloadElementIds(std::set<Int64> & unloadedElementIds) const = 0;
#pragma endregion

#pragma region 内部-请勿调用
        /// \brief 【仅供内部使用】强制修改所有对象
        virtual bool ForceModifyAllElements(std::wstring* errorMessage) = 0;
#pragma endregion

        /// \brief 获取非const版本的Document
        ///
        /// \return 返回非const版本的Document
        virtual IDocument* GetDocument() const = 0;

        /// \brief 保存文档到当前文件
        ///
        /// 需要先调用SaveAs()给出文件路径
        /// \param saveOptions 保存选项
        /// \param errorCode 文档保存错误码
        /// \return 成功返回true，失败返回false
        /// \see SaveAs()
        GCMP_OBSOLETE_API(2021 / 09 / 01, IDocument::Save(const DocumentSaveOptions&, DocumentSaveResult&)) virtual bool Save(const DocumentSaveOptions & saveOptions, DocumentSaveError & errorCode) = 0;
        
        /// \brief 另存文档
        ///
        /// 如有后续修改和保存，修改会存入这里指定的路径
        /// \param filePath 文档另存的路径
        /// \param saveOptions 保存选项
        /// \param errorCode 文档保存错误码
        /// \return 成功返回true，失败返回false
        GCMP_OBSOLETE_API(2021 / 09 / 01, IDocument::SaveAs(const std::wstring&, const DocumentSaveOptions&, DocumentSaveResult&)) virtual bool SaveAs(const std::wstring & filePath, const DocumentSaveOptions & saveOptions, DocumentSaveError & errorCode) = 0;
        
        /// \brief 备份文档到指定文件
        ///
        /// 和SaveAs()不同，BackupToFile()不改变当前文件，如有后续修改和保存，修改还会存入当前文件。
        /// BackupToFile()不影响当前文档状态。
        /// \param filePath 文档存入的路径。不能和当前路径相同，否则返回false和DocumentSaveError::InvalidPath错误码。
        /// \param errorCode 文档保存错误码
        /// \return 成功返回true，失败返回false
        /// \see SaveAs()
        GCMP_OBSOLETE_API(2021 / 09 / 01, const std::wstring&, DocumentSaveResult&) virtual bool BackupToFile(const std::wstring& filePath, DocumentSaveError& errorCode) = 0;

        /// \brief 备份数据集关联的文档到新文档中
        ///
        /// 不改变当前数据集关联的文档，如有后续修改和保存，修改还会存入当前文档。
        /// 备份出的文档将以IDocument对象形式提供
        /// \param filePath 备份的新文档路径，以.gac结尾，如果路径已存在则覆盖，如果路径文件已存在并处于打开状态则不备份返回nullptr
        /// \param datasetSubId 新数据集的Sub-Id
        /// \param errorCode 文档保存错误码
        /// \return 成功返回新的文档智能指针，失败返回nullptr
        GCMP_OBSOLETE_API(2021 / 09 / 01, const std::wstring&, UInt16, DocumentSaveResult&) virtual IDocument* BackupForDataset(const std::wstring& filePath, UInt16 datasetSubId, DocumentSaveError& errorCode) = 0;
       
    };
}

